﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.Media;
using System.Reflection;
using System.IO;

namespace FetionLite
{
    public partial class MainForm : Form
    {
        private class ChatUI
        {
            public DialogForm ChatWindow
            {
                get;
                set;
            }

            public MenuItemEx WindowMenuItem
            {
                get;
                set;
            }

            public ListViewItem ContactListViewItem
            {
                get;
                set;
            }

            public ChatUI()
            {
            }

            public ChatUI(DialogForm chatWindow, MenuItemEx windowMenuItem)
            {
                this.ChatWindow = chatWindow;
                this.WindowMenuItem = windowMenuItem;
            }
        }

        private Dictionary<FetionAccount, ChatUI> chatUIDic = new Dictionary<FetionAccount, ChatUI>();
        private Dictionary<FetionAccount, List<string>> contactMessagesDic = new Dictionary<FetionAccount, List<string>>();
        private TimedHintManager _timedHintMrg;
        private string _currentPath;
        private string _wavePath;
        private static Sound _sound;

        public MainForm()
        {
            InitializeComponent();

            _timedHintMrg = new TimedHintManager(SetStatus);
        }

        private void MainForm_Load(object sender, EventArgs e)
        {
            _currentPath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase);
            _wavePath = Path.Combine(_currentPath, "Standard.wav");

            //预装载声音资源，优先使用自定义声音文件
            if (File.Exists(_wavePath))
                _sound = new Sound(_wavePath);
            else
                _sound = new Sound(Assembly.GetExecutingAssembly().GetManifestResourceStream("FetionLite.Standard.wav"));

            Fetion.Instance.OnAccountUpdateOK += new Fetion.AccountUpdateOKDeletegate(OnAccountUpdateOK);
            Fetion.Instance.OnNewMessage += new Fetion.NewMessageDeletegate(OnNewMessage);
            Fetion.Instance.OnAccountOnlineStatusChanged += new Fetion.AccountOnlineStatusChangedDelegate(OnAccountOnlineStatusChange);

            LoginForm f = new LoginForm();
            f.Owner = this;
            f.ShowDialog();

            if (f.LoginSuccessed)
            {
                InitContactList();

                List<FetionAccount> accouts = Fetion.Instance.GetAccountList();
                foreach (FetionAccount account in accouts)
                    Fetion.Instance.UpdateAccountById(account.Id);

            }
            else
            {
                this.Close();
            }

            this.miSound.Click -= new EventHandler(miSound_Click);
            this.miVibrate.Click -= new EventHandler(miVibrate_Click);

            this.miSound.Checked = FetionLiteSettings.Instance.EnableSound;
            this.miVibrate.Checked = FetionLiteSettings.Instance.EnableVibrate;

            this.miSound.Click += new EventHandler(miSound_Click);
            this.miVibrate.Click += new EventHandler(miVibrate_Click);
        }

        void OnAccountOnlineStatusChange(FetionAccount account, FetionUserStatus status)
        {
            FxAccountTreeNode node = FindAccountNodeById(account.Id);
            node.Account.OnlineStatus = status;
            node.UpdateText();
        }

        void OnAccountUpdateOK(FetionAccount account)
        {
            _timedHintMrg.CreateTimedHint(3000, string.Format("{0}资料更新成功...", account.Id.ToString()));

            UpdateContactList(account);
            for (int i = 0; i < tvContact.Nodes.Count; i++)
            {
                FxGroupTreeNode gn = tvContact.Nodes[i] as FxGroupTreeNode;
                if (gn != null)
                {
                    gn.UpdateText();
                }
            }
        }

        void OnNewMessage(FetionAccount fromAccount, FetionMsg msg)
        {
            if (fromAccount.Id == 10000)
            {
                MessageBox.Show(msg.PlainMessage, "系统消息", MessageBoxButtons.OK, MessageBoxIcon.Asterisk, MessageBoxDefaultButton.Button1);
            }
            else
            {
                FxAccountTreeNode node = FindAccountNodeById(fromAccount.Id);

                //非联系人？？
                if (node == null)
                {
                    node = AddNewAccountToContactList(fromAccount);
                }

                if (node != null && node.DialogForm != null)
                {
                    node.DialogForm.AppendMessage(msg);
                }
                else
                {
                    node.EnqueueMessage(msg);
                }

                _timedHintMrg.CreateTimedHint(3000, string.Format("{0} 给你发送了新信息...", node.Account.ShowName));
            }

            if (FetionLiteSettings.Instance.EnableSound)
            {
                _sound.Play();
            }

            if (FetionLiteSettings.Instance.EnableVibrate)
            {
                LED.Vibrate(1000);
            }
        }

        private FxAccountTreeNode FindAccountNodeById(int id)
        {
            FxAccountTreeNode accoutNode = null;

            for (int i = 0; i < tvContact.Nodes.Count; i++)
            {
                FxGroupTreeNode groupNode = tvContact.Nodes[i] as FxGroupTreeNode;

                var nodes = from FxAccountTreeNode node in groupNode.Nodes
                            where node.Account.Id == id
                            select node;

                if (nodes.Any())
                {
                    accoutNode = nodes.Single();
                    break;
                }
            }

            return accoutNode;
        }

        private void fetion_OnDeregistered(object sender, EventArgs e)
        {
            //LogoutFx();
            //MessageBox.Show("用户已从其他客户端登陆,系统退出");
            //this.Close();
            ////sc.Post(AlterLoginBtn, true);
        }

        private void UpdateContactList(FetionAccount c)
        {
            if (this.InvokeRequired)
                this.BeginInvoke(new UpdateContactListDelegate(SelfUpdateContactList), c);
            else
                SelfUpdateContactList(c);
        }

        public delegate void UpdateContactListDelegate(FetionAccount account);
        private void SelfUpdateContactList(FetionAccount account)
        {
            FxAccountTreeNode contactCurNode = null;

            foreach (FxGroupTreeNode groupNode in tvContact.Nodes)
            {
                var accountNode = from FxAccountTreeNode node in groupNode.Nodes
                                  where node.Account.Id == account.Id
                                  select node;

                if (accountNode.Any())
                {
                    contactCurNode = accountNode.Single();
                    contactCurNode.Account = account;
                    break;
                }
            }

            contactCurNode.UpdateText();
        }

        private void InitContactList()
        {
            List<FetionGroup> groups = Fetion.Instance.GetGroupList();
            List<FetionAccount> accounts = Fetion.Instance.GetAccountList();

            //a unknown group
            FetionGroup g = new FetionGroup() { Id = 0, Name = "未分组" };
            groups.Add(g);

            this.tvContact.BeginUpdate();

            this.tvContact.Nodes.Clear();

            foreach (FetionGroup fxgroup in groups)
            {
                FxGroupTreeNode groupNode = new FxGroupTreeNode(fxgroup.Name);
                groupNode.Group = fxgroup;

                var groupAccounts = from a in accounts
                                    where a.GroupId == fxgroup.Id
                                    select a;

                foreach (var account in groupAccounts)
                {
                    FxAccountTreeNode acountNode = new FxAccountTreeNode(account.Id.ToString());
                    acountNode.Account = account;

                    groupNode.Nodes.Add(acountNode);
                }

                tvContact.Nodes.Add(groupNode);
            }

            this.tvContact.EndUpdate();

        }

        private FxAccountTreeNode AddNewAccountToContactList(FetionAccount account)
        {
            if (this.InvokeRequired)
                return (FxAccountTreeNode)this.Invoke(new SelfAddNewAccountToContactListDelegate(SelfAddNewAccountToContactList), account);
            else
                return SelfAddNewAccountToContactList(account);
        }

        private delegate FxAccountTreeNode SelfAddNewAccountToContactListDelegate(FetionAccount account);
        private FxAccountTreeNode SelfAddNewAccountToContactList(FetionAccount account)
        {
            for (int i = 0; i < this.tvContact.Nodes.Count; i++)
            {
                FxGroupTreeNode groupNode = this.tvContact.Nodes[i] as FxGroupTreeNode;
                if (groupNode != null)
                {
                    FxAccountTreeNode accountNode = new FxAccountTreeNode(account.ShowName);
                    accountNode.Account = account;

                    groupNode.Nodes.Add(accountNode);

                    return accountNode;
                }
            }

            return null;
        }

        void chatWindow_Deactivate(object sender, EventArgs e)
        {
            DialogForm f = sender as DialogForm;
            if (this.chatUIDic.ContainsKey(f.Account))
            {
                if (this.chatUIDic[f.Account].WindowMenuItem != null)
                    this.chatUIDic[f.Account].WindowMenuItem.Checked = false;
            }
        }

        void chatWindow_Activated(object sender, EventArgs e)
        {
            DialogForm f = sender as DialogForm;
            if (this.chatUIDic.ContainsKey(f.Account))
            {
                this.chatUIDic[f.Account].WindowMenuItem.Checked = true;
            }
        }

        void chatWindow_Closed(object sender, EventArgs e)
        {
            DialogForm f = sender as DialogForm;
            if (f != null)
            {
                this.miAction.MenuItems.Remove(this.chatUIDic[f.Account].WindowMenuItem);
                this.chatUIDic[f.Account].ChatWindow = null;
                this.chatUIDic[f.Account].WindowMenuItem = null;

                f.Dispose();
            }
        }

        delegate void SetStatusTextDelegate(string statusText);
        private void SetStatus(string statusText)
        {
            SetStatusTextDelegate setStatusText = SetStatusText;

            if (this.InvokeRequired)
            {
                this.BeginInvoke(setStatusText, statusText);
            }
            else
            {
                setStatusText(statusText);
            }           
        }

        private void SetStatusText(string statusText)
        {
            lblStatus.Text = statusText;
        }

        //void chatWindowMenuItem_Click(object sender, EventArgs e)
        //{
        //    MenuItemEx senderMI = sender as MenuItemEx;
        //    Contact senderContact = senderMI.Tag as Contact;
        //    if (chatUIDic.ContainsKey(senderContact))
        //        chatUIDic[senderContact].ChatWindow.Activate();
        //}

        private void miExit_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("确定退出吗？",
                "确认退出",
                MessageBoxButtons.OKCancel,
                MessageBoxIcon.Question,
                MessageBoxDefaultButton.Button2) == DialogResult.OK)
            {
                FetionLiteSettings.Instance.Persist();
                this.Close();
            }
        }

        private void miSound_Click(object sender, EventArgs e)
        {
            miSound.Checked = !miSound.Checked;
            FetionLiteSettings.Instance.EnableSound = miSound.Checked;
        }

        private void miVibrate_Click(object sender, EventArgs e)
        {
            miVibrate.Checked = !miVibrate.Checked;
            FetionLiteSettings.Instance.EnableVibrate = miVibrate.Checked;
        }

        private void tvContact_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                TreeView tv = sender as TreeView;
                TreeNode node = tv.SelectedNode;
                if (node != null && node.Parent != null)
                {
                    FxAccountTreeNode accountNode = node as FxAccountTreeNode;
                    if (accountNode.DialogForm != null)
                    {
                        accountNode.DialogForm.Activate();
                    }
                    else
                    {
                        DialogForm dialogForm = new DialogForm(accountNode.Account);
                        accountNode.DialogForm = dialogForm;
                        dialogForm.Closed += new EventHandler(dialogForm_Closed);

                        dialogForm.Show();

                        while (accountNode.UnreadMessageCount > 0)
                            dialogForm.AppendMessage(accountNode.DequeueMessage());

                    }
                }
            }
        }

        void dialogForm_Closed(object sender, EventArgs e)
        {
            DialogForm dialogForm = sender as DialogForm;
            FxAccountTreeNode accountNode = FindAccountNodeById(dialogForm.Account.Id);
            if (accountNode != null)
            {
                accountNode.DialogForm = null;
            }
        }
    }
}